#include "Common/utils.h"

#ifdef _WIN32
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif

namespace Basic
{
	bool isLetter(char ch)
	{
		// A-Z || a-z
		if ((ch > 64 && ch < 91) || (ch > 96 && ch < 123))
			return true;
		return false;
	}

	bool isNumber(const string &token)
	{
		return std::regex_match(token, std::regex(("(\\+|-)?([0-9]*\\.[0-9]+|[0-9]+\\.?)([Ee][+-]?[0-9]+)?")));
	}

	string strip(const string &str, char ch)
	{
		// 除去str两端的ch字符
		int i = 0;
		size_t length = str.size();

		while (i < length && str[i] == ch) // 头部ch字符个数是i
			i++;
		if (i >= length)
			return "";

		int j = str.size() - 1;
		while (j >= 0 && str[j] == ch) // 尾部ch字符个数
			j--;
		return str.substr(i, j + 1 - i);
	}

	vector<string> split(const string &str, const string &regex_str)
	{
		std::regex regexz(regex_str);
		std::vector<std::string> list(std::sregex_token_iterator(str.begin(), str.end(), regexz, -1), std::sregex_token_iterator());
		return list;
	}

	std::optional<string> readfile(const string& file_path)
	{
		std::ifstream ifs;
		ifs.exceptions(std::ifstream::failbit);
		try
		{
			ifs.open(file_path);
			string text((std::istreambuf_iterator<char>(ifs)),
				(std::istreambuf_iterator<char>()));
			ifs.close();
			return text;
		}
		catch (const std::exception& e)
		{
			return std::nullopt;
		}
	}

	void printf(const char *s)
	{
		while (*s)
		{
			if (*s == '%' && *++s != '%')
				throw std::runtime_error("invalid format string: missing arguments");
			std::cout << *s++;
		}
	}

	vector<keyword> keywords{
	{(const char*)"var", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"Declare or Assign a variable", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"var IDENTIFIER = expr", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"del", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"Delete a variable", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"del IDENTIFIER", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"if", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"if control statement", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"if <condition> then <do sth>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"then", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"then <do sth>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"then <do sth>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"elif", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"elif control statement", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"elif <condition> then <do sth>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"else", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"else control statement", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"else <do sth> end", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"while", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"while loop", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"while <condition> then <do sth>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"for", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"for loop", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"for <var>=<value> to <end_value> step <step_value> then <do sth>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"to", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"to for loop limit", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"to <end_value>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"step", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"step of each for loop", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"step <step_value>, default 1", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"break", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"break from loop", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"continue", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"Continue loop", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"return", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char*)"return from function", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"return <variable/expression>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"func", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"func definition", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"func (name)?(args)-> statement | func (name)?(args): statements", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"end", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"end of a multiline statements", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"and", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"logic operator and", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"or", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"logic operator or", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"not", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"logic operator not", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"null", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"represent NULL", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"true", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"bool true", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"false", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"bool false", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"M_PI", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char*)"M_PI = 3.14159265354", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},

	// <built-in functions>
	{(const char*)"run", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"run a script from file", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"run(filepath), be aware of using / or \\\\", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"print", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"print a value", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"print(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"prints", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"prints a list of value", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"prints(list_of_value, ends_with), e.g prints([1,\"2\",3.3],\"\\n\")", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"print_ret", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"print and return a value", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"print_ret(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"input", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Receive user input as String", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"input()", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"input_num", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Receive user input as Number", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"input_num()", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"clear", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"clear screen", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"clear()", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"is_num", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Check if given value is Number", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"is_num(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"is_str", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Check if given value is String", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"is_str(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"is_list", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Check if given value is List", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"is_list(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"is_func", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Check if given value is Function", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"is_func(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"len", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Count the length of given List", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"len(list)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"append", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"append elem to list(mutable)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"append(list, elem)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"pop", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Remove elem at given index in list(mutable)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"pop(list, index)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"pop_back", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Remove the last elem in list(mutable)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"pop_back(list)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"pop_front", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Remove the first elem in list(mutable)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"pop_front(list)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"extend", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Concatenate list2 to list1(mutable)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"extend(list1, list2)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{(const char*)"swap", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char*)"Swap two variable, use & to pass reference", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char*)"swap(var1, var2)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
	{nullptr, CROSSLINE_COLOR_DEFAULT, nullptr, CROSSLINE_COLOR_DEFAULT, nullptr, CROSSLINE_COLOR_DEFAULT} };

	void completion_hook(const char *buf, crossline_completions_t *pCompletion)
	{
		string last_input = split(string(buf), "[ ,\(]").back();

		for (keyword const &p : keywords)
		{
			if (p.word == nullptr)
				break;

			if (strncmp(last_input.c_str(), p.word, strlen(last_input.c_str())) == 0)
			{
				// 如果全字匹配，则显示提示
				if (last_input == p.word)
				{
					if (p.hint != nullptr)
						crossline_hints_set_color(pCompletion, p.hint, p.hi_color);
					break;
				}
				// 否则去找匹配项
				crossline_completion_add_color(pCompletion, p.word, p.w_color, p.help, p.he_color);
			}
		}
	}
}